#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <random>
#include <chrono>

// 方向数组，用于遍历相邻方格
const int dx[] = {-1, 0, 1, -1, 1, -1, 0, 1};
const int dy[] = {-1, -1, -1, 0, 0, 1, 1, 1};

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::GameMainWindow)
{
    ui->setupUi(this);
    ui->MinesWidget->verticalHeader()->hide(); //隐藏行号和列号
    ui->MinesWidget->horizontalHeader()->hide();

    connect(ui->FlagLabel, &QPushButton::clicked, this, &MainWindow::onDebugButtonClick);
    connect(ui->TimeLabel, &QPushButton::clicked, this, &MainWindow::onTimeButtonClick);
    connect(timer, &QTimer::timeout, this, &MainWindow::updateTimerDisplay);
    connect(ui->RestartButton, &QPushButton::clicked, this, &MainWindow::onRestartButtonClick);
    connect(ui->SettingButton, &QPushButton::clicked, this, &MainWindow::onSettingButtonClick);
    connect(ui->RankButton, &QPushButton::clicked, this, &MainWindow::onRankingButtonClick);

    createMines();
    game_state = 1;
    timer->start(1000);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::addRecordToDatabase(const string& name_sq, int row_sq, int col_sq, int mines_sq, int time_sq) {
    cout << "name:" << name_sq << " time:" << time_sq << " row:" << row_sq << " col:" << col_sq << " mines:" << mines_sq << endl;
    sqlite3 *db;
    int rc;

    // 打开或创建数据库
    rc = sqlite3_open_v2("mines.db", &db,
                             SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, NULL);
    if(rc != SQLITE_OK)
    {
       cerr << "Failed to create database file:" << sqlite3_errmsg(db) << endl;
       return;
    }

    // 创建表格，如果表格不存在
    char *err;
    const char* createTableSql =
        "CREATE TABLE IF NOT EXISTS record ("
        "    name TEXT,"
        "    row INTEGER,"
        "    col INTEGER,"
        "    mines INTEGER,"
        "    time INTEGER"
        ");";

    sqlite3_exec(db, createTableSql, NULL, NULL, &err);
    if (err != SQLITE_OK) {
        cerr << "SQL error: " << sqlite3_errmsg(db) << endl;
        sqlite3_close(db);
        return;
    }

    // 插入数据
    stringstream ss;
    ss << "INSERT INTO record (name, row, col, mines, time) VALUES ('" << name_sq << "', " << row_sq << ", " << col_sq << ", " << mines_sq << ", " << time_sq << ")";

    sqlite3_exec(db, ss.str().c_str(), NULL, NULL, &err);
    if (err != SQLITE_OK) {
        cerr << "SQL error: " << sqlite3_errmsg(db) << endl;
        sqlite3_close(db);
        return;
    }

    sqlite3_close(db);
}

void MainWindow::onDebugButtonClick() {
    if (debug_mode)
    {
        QIcon icon;
        icon.addFile(QString::fromUtf8(":/imgs/imgs/game.png"), QSize(), QIcon::Normal, QIcon::On);
        ui->FlagLabel->setIcon(icon);
        debug_mode = 0;
    }
    else {
        QIcon icon;
        icon.addFile(QString::fromUtf8(":/imgs/imgs/debug.png"), QSize(), QIcon::Normal, QIcon::On);
        ui->FlagLabel->setIcon(icon);
        debug_mode = 1;
    }
}

void MainWindow::onTimeButtonClick(){
    if (game_state == 1){
        game_state = 2;
        timer->stop();
        QIcon icon;
        icon.addFile(QString::fromUtf8(":/imgs/imgs/time_pause.png"), QSize(), QIcon::Normal, QIcon::On);
        ui->TimeLabel->setIcon(icon);
    }
    else if (game_state == 2) {
        game_state = 1;
        timer->start(1000);
        QIcon icon;
        icon.addFile(QString::fromUtf8(":/imgs/imgs/time.png"), QSize(), QIcon::Normal, QIcon::On);
        ui->TimeLabel->setIcon(icon);
    }
}

void MainWindow::updateTimerDisplay(){
    secondsElapsed++;

    // 将秒数转换为HH:MM:SS格式
    QTime time(0, 0, 0);
    time = time.addSecs(secondsElapsed);
    ui->TimeLabel->setText(time.toString());
}

void MainWindow::onRestartButtonClick() {
    clearMines();
    createMines();
    game_state = 1;
    flags_num = 0;
    opened_num = 0;
    ui->FlagLabel->setText(QString::fromStdString(to_string(flags_num)+"/"+to_string(mines_num)));
    secondsElapsed = 0;
    ui->TimeLabel->setText("00:00:00");
    timer->start(1000);
}

void MainWindow::onSettingButtonClick() {
    // 创建一个对话框
    QDialog dialog;
    dialog.setWindowTitle("Set Level");
    QIcon icon;
    icon.addFile(QString::fromUtf8(":/imgs/imgs/setting.png"), QSize(), QIcon::Normal, QIcon::On);
    dialog.setWindowIcon(icon);

    // 创建表单布局
    QFormLayout *formLayout = new QFormLayout(&dialog);

    // 添加三个数字输入框
    QLineEdit *input1 = new QLineEdit(&dialog);
    QLineEdit *input2 = new QLineEdit(&dialog);
    QLineEdit *input3 = new QLineEdit(&dialog);

    // 设置输入框的验证器，只允许输入整数
    input1->setValidator(new QIntValidator(0, 99, input1));
    input2->setValidator(new QIntValidator(0, 99, input2));
    input3->setValidator(new QIntValidator(0, 999, input3));

    // 将输入框添加到布局中
    formLayout->addRow("Row:", input1);
    formLayout->addRow("Col:", input2);
    formLayout->addRow("Mines:", input3);

    // 创建按钮框，包含OK和Cancel按钮
    QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
    connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
    connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);

    // 将按钮框添加到布局中
    formLayout->addWidget(buttonBox);

    // 显示对话框并等待用户交互
    int result = dialog.exec();

    if (result == QDialog::Accepted)
    {
        // 如果用户点击了OK按钮，获取输入的数字并输出
        int num1 = input1->text().toInt();
        int num2 = input2->text().toInt();
        int num3 = input3->text().toInt();

        if (!(num1>=2 && num1 <= 20) || !(num2>=2 && num2 <= 30) || !(num3>=1 || num3 <= (num1*num2-1))) {
            // 创建一个信息消息框
                QMessageBox msgBox;
                msgBox.setWindowIcon(icon);
                // 设置消息框的标题
                msgBox.setWindowTitle("Invalid Input");
                // 设置消息框的文本，这里使用setInformativeText可以添加额外的详细信息
                msgBox.setText("Row: 2 ~ 20\nCol: 2 ~ 30\nMines: 1 ~ Row*Col-1");
//                msgBox.setInformativeText("Here is the second line of information.\nAnd here is the third line.");
                // 显示消息框
                msgBox.exec();;
        }
        else{
            row = num1;
            col = num2;
            mines_num = num3;
            onRestartButtonClick();
        }
    }
}

// 回调函数，用于处理查询结果
static int callback(void *data, int argc, char **argv, char **azColName){
    int i;
    cout << "| ";
    for(i = 0; i<argc; i++){
        cout << azColName[i] << ": " << (argv[i] ? argv[i] : "NULL") << " | ";
    }
    cout << endl;
    return 0;
}

void MainWindow::onRankingButtonClick() {
    sqlite3 *db;
    int rc;
    string sql;
    char *err;
    int n = 0;

    // 打开数据库
    rc = sqlite3_open_v2("mines.db", &db,
                             SQLITE_OPEN_READWRITE, NULL);
    if(rc != SQLITE_OK)
    {
       cerr << "Failed to open database file:" << sqlite3_errmsg(db) << endl;
       return;
    }

    // 构建SQL查询语句，选择每个组中时间最小的记录
    // 然后再次查询，使用子查询的结果，获取完整的记录
    sql =
        "SELECT *\n"
        "FROM record r\n"
        "WHERE (r.name, r.row, r.col, r.mines, r.time) IN (\n"
        "    SELECT name, row, col, mines, MIN(time)\n"
        "    FROM record\n"
        "    GROUP BY name, row, col, mines\n"
        ");";

    // 执行SQL查询
    cout << "Record" << endl;
    sqlite3_exec(db, sql.c_str(), callback, 0, &err);
    if (err != SQLITE_OK) {
        cerr << "SQL error: " << sqlite3_errmsg(db) << endl;
        sqlite3_close(db);
        return;
    }

    sqlite3_close(db);
}

void MainWindow::createMines()
{
    this->setMinimumSize(QSize(35*col+145, 35*row+30));
    // 初始化地雷表
    mines_state = vector<vector<int>>(row, vector<int>(col, 0));
    flags_state = vector<vector<int>>(row, vector<int>(col, 0));

    // 初始化随机数生成器
    auto now = chrono::system_clock::now();
    auto now_time_t = chrono::system_clock::to_time_t(now);
    seed_seq seed{now_time_t};
    mt19937 gen(seed);
    uniform_int_distribution<int> row_dist(0, row - 1);
    uniform_int_distribution<int> col_dist(0, col - 1);

    // 随机放置雷
    int mines_placed = 0;
    while (mines_placed < mines_num) {
        int i = row_dist(gen);
        int j = col_dist(gen);
        // 检查这个位置是否还没有放置雷
        if (mines_state[i][j] != -1) {
            mines_state[i][j] = -1; // 放置雷
            ++mines_placed;
        }
    }

    // 计算周围地雷数
    int mines_count = 0;
    for (int i = 0; i < row; i++){
        for (int j = 0; j < col; j++){
            mines_count = 0;
            if (mines_state[i][j] != -1){
                for(int k = 0; k < 8; k++){
                    if ((i + dx[k] >= 0) && (i + dx[k] < row) && (j + dy[k] >= 0) && (j + dy[k] < col)){
                        if (mines_state[i + dx[k]][j + dy[k]] == -1){
                            mines_count++;
                        }
                    }
                }
              mines_state[i][j] = mines_count;
            }
        }
    }

    // 设置 MinesWidget 的行数和列数
    ui->MinesWidget->setRowCount(row);
    ui->MinesWidget->setColumnCount(col);

    // 设置行和列的大小策略
    for (int i = 0; i < col; ++i) {
        ui->MinesWidget->horizontalHeader()->setSectionResizeMode(i, QHeaderView::Stretch);
    }
    for (int i = 0; i < row; ++i) {
        ui->MinesWidget->verticalHeader()->setSectionResizeMode(i, QHeaderView::Stretch);
    }

    // 为 MinesWidget 添加 QPushButton
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            QPushButton *button = new QPushButton();
            button->setObjectName(QString("btn_%1_%2").arg(i).arg(j));
            button->installEventFilter(this); // 安装事件过滤器
            button->setFont(QFont("Microsoft YaHei", 20, QFont::Bold));
            button->setStyleSheet("QPushButton {background:#ede3d7;border-radius: 10px;border:5px solid #b8aea0;}\n"
                                  "QPushButton:hover {background:#fbf9ef;}");
            ui->MinesWidget->setCellWidget(i, j, button); // 将按键添加到表格中
        }
    }
}

void MainWindow::clearMines()
{
    // 清空地雷表
    mines_state.clear();
    flags_state.clear();

    // 删除地雷按键
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            QWidget *widget = ui->MinesWidget->cellWidget(i, j);
            if (widget) {
                // 删除单元格中的按钮
                ui->MinesWidget->removeCellWidget(i, j);
                // 删除按钮对象
                delete widget;
            }
        }
    }
}

void MainWindow::overGame(bool success, int x, int y){
    QWidget *widget = ui->MinesWidget->cellWidget(y, x);
    QPushButton *button = qobject_cast<QPushButton*>(widget);
    game_state = 0;
    timer->stop();
    QTime time(0, 0, 0);
    time = time.addSecs(secondsElapsed);
    QString timeString = time.toString("hh:mm:ss");
    if (success) {
        cout << "Game Over: You Succeeded!" << endl;

        // 创建一个对话框
        QDialog dialog;
        dialog.setWindowTitle("Congratulations!");
        QIcon icon;
        icon.addFile(QString::fromUtf8(":/imgs/imgs/rank.png"), QSize(), QIcon::Normal, QIcon::On);
        dialog.setWindowIcon(icon);

        // 创建表单布局
        QFormLayout *formLayout = new QFormLayout(&dialog);

        // 添加提示标签
        string s = "You Succeeded! Level:"+to_string(mines_num)+"/"+to_string(row)+"*"+to_string(col)+", Use:"+timeString.toStdString().c_str();
        formLayout->addRow(new QLabel(QString::fromStdString(s), &dialog));

        // 添加名字输入框
        QLineEdit *nameEdit = new QLineEdit(&dialog);
        formLayout->addRow("Please input your name:", nameEdit);

        // 创建按钮框，包含OK和Cancel按钮
        QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
        connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
        connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);

        // 将按钮框添加到布局中
        formLayout->addWidget(buttonBox);

        // 显示对话框并等待用户交互
        int result = dialog.exec();

        if (result == QDialog::Accepted)
        {
            // 如果用户点击了OK按钮，获取输入的名字并输出
            const QString name = nameEdit->text();
            addRecordToDatabase(name.toStdString().c_str(), row, col, mines_num, secondsElapsed);
        }
    }
    else {
        cout << "Game Over: You Failed!" << endl;
        if (button) {
            button->setStyleSheet("QPushButton {background:#FF0000;border-radius: 10px;border:5px solid #b8aea0;}");
        }
    }

    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            widget = ui->MinesWidget->cellWidget(i, j);
            button = qobject_cast<QPushButton*>(widget);
            if (button) {
                if (mines_state[i][j] == -1) {
                    if (flags_state[i][j] == 2) {
                        QIcon icon;
                        icon.addFile(QString::fromUtf8(":/imgs/imgs/mines_out.png"), QSize(), QIcon::Normal, QIcon::On);
                        button->setIcon(icon);
                        button->setIconSize(button->size());
                    }
                    else {
                        QIcon icon;
                        icon.addFile(QString::fromUtf8(":/imgs/imgs/mines.png"), QSize(), QIcon::Normal, QIcon::On);
                        button->setIcon(icon);
                        button->setIconSize(button->size());
                    }
                }
            }
        }
    }

}

void MainWindow::changeMinesFlags(int x, int y, int flag){
    QWidget *widget = ui->MinesWidget->cellWidget(y, x);
    if (QPushButton *button = qobject_cast<QPushButton*>(widget)) {
        if (flag == 1){
            if (mines_state[y][x] != -1) {
                button->setStyleSheet("QPushButton {background:#d3cbc1;border-radius: 10px;border:5px solid #b8aea0;}\n"
                                      "QPushButton:hover {}");
                if (mines_state[y][x] > 0){
                    button->setText(QString::fromStdString(to_string(mines_state[y][x])));
                    QPalette palette = button->palette();
                    switch(mines_state[y][x]){
                        case 1:
                            palette.setColor(QPalette::ButtonText, Qt::gray);
                            break;
                        case 2:
                            palette.setColor(QPalette::ButtonText, Qt::darkGray);
                            break;
                        case 3:
                            palette.setColor(QPalette::ButtonText, Qt::white);
                            break;
                        case 4:
                            palette.setColor(QPalette::ButtonText, Qt::blue);
                            break;
                        case 5:
                            palette.setColor(QPalette::ButtonText, Qt::yellow);
                            break;
                        case 6:
                            palette.setColor(QPalette::ButtonText, Qt::darkRed);
                            break;
                        case 7:
                            palette.setColor(QPalette::ButtonText, Qt::red);
                            break;
                        case 8:
                            palette.setColor(QPalette::ButtonText, Qt::black);
                            break;
                        default:
                            palette.setColor(QPalette::ButtonText, Qt::black);
                            break;
                    }
                    button->setPalette(palette);
                }
            }
        }
        else if (flag == 2){
            QIcon icon;
            icon.addFile(QString::fromUtf8(":/imgs/imgs/flag.png"), QSize(), QIcon::Normal, QIcon::On);
            button->setIcon(icon);
            button->setIconSize(button->size());
        }
        else {
            button->setIcon(QIcon());
        }
    }
}

void MainWindow::dfs(int x, int y){
    // 检查边界
    if (x < 0 || x >= col || y < 0 || y >= row) {
        return;
    }

    //是雷或已打开或已插旗则不操作
    if (mines_state[y][x] == -1 || flags_state[y][x] == 1 || flags_state[y][x] == 2) {
        return;
    }

    //标记方格被打开
    flags_state[y][x] = 1;
    changeMinesFlags(x, y, 1);
    opened_num++;


    //周围有雷停止递归
    if (mines_state[y][x] > 0) {
        return;
    }

    //遍历相邻方格
    for (int i = 0; i < 8; i++){
        dfs(x + dx[i], y + dy[i]);
    }
}

// 左击地雷
void MainWindow::onLeftButtonClick(int x, int y) {
    if (game_state == 2){
        game_state = 1;
        timer->start(1000);
        QIcon icon;
        icon.addFile(QString::fromUtf8(":/imgs/imgs/time.png"), QSize(), QIcon::Normal, QIcon::On);
        ui->TimeLabel->setIcon(icon);
    }
    if (game_state == 1){
        if (flags_state[y][x] == 0){
            if (mines_state[y][x] == -1){
                if (!debug_mode){
                    overGame(false, x, y);
                }
                else {
                    cout << "You clicked on mines." << endl;
                }
            }
            else {
                dfs(x, y);
                if (opened_num == row * col - mines_num) {
                    overGame(true, x, y);
                }
            }
        }
    }
}

// 右击地雷
void MainWindow::onRightButtonClick(int x, int y) {
    if (game_state == 2){
        game_state = 1;
        timer->start(1000);
        QIcon icon;
        icon.addFile(QString::fromUtf8(":/imgs/imgs/time.png"), QSize(), QIcon::Normal, QIcon::On);
        ui->TimeLabel->setIcon(icon);
    }
    if (game_state == 1){
        if (flags_state[y][x] == 0){
            flags_state[y][x] = 2;
            flags_num++;
        }
        else if (flags_state[y][x] == 2){
            flags_state[y][x] = 0;
            flags_num--;
        }
        ui->FlagLabel->setText(QString::fromStdString(to_string(flags_num)+"/"+to_string(mines_num)));
        changeMinesFlags(x, y, flags_state[y][x]);
    }
}

// eventFilter函数
bool MainWindow::eventFilter(QObject *watched, QEvent *event) {
    if (event->type() == QEvent::MouseButtonPress) {
        QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
        QPushButton *button = qobject_cast<QPushButton*>(watched);
        if (button) {
            QString objectName = button->objectName();
            QStringList parts = objectName.split("_");
            int y = parts[1].toInt();
            int x = parts[2].toInt();
//            qDebug() << x << endl;
//            qDebug() << y << endl;

            if (mouseEvent->button() == Qt::LeftButton) {
                onLeftButtonClick(x, y);
            } else if (mouseEvent->button() == Qt::RightButton) {
                onRightButtonClick(x, y);
            }
        }
    }
    // 继续传递事件到其他事件处理器
    return QObject::eventFilter(watched, event);
}
